#include "JsonRpcNotification.h"
#include <gtest/gtest.h>
#include <QJsonObject>
#include <QJsonArray>

class TestJsonRpcNotification : public ::testing::Test
{
protected:
    void SetUp() override {}
    void TearDown() override {}
};

TEST_F(TestJsonRpcNotification, DefaultConstructor)
{
    JsonRpcNotification notification;
    
    EXPECT_TRUE(notification.method().isEmpty());
    EXPECT_TRUE(notification.params().isEmpty());
    EXPECT_FALSE(notification.hasParams());
    EXPECT_FALSE(notification.hasId());
    EXPECT_FALSE(notification.isValid());
}

TEST_F(TestJsonRpcNotification, ConstructorWithMethod)
{
    JsonRpcNotification notification("testMethod");
    
    EXPECT_EQ(notification.method(), QString("testMethod"));
    EXPECT_TRUE(notification.params().isEmpty());
    EXPECT_FALSE(notification.hasParams());
    EXPECT_FALSE(notification.hasId());
    EXPECT_TRUE(notification.isValid());
}

TEST_F(TestJsonRpcNotification, ConstructorWithMethodAndParams)
{
    QJsonObject params;
    params["param1"] = "value1";
    params["param2"] = 123;
    
    JsonRpcNotification notification("testMethod", params);
    
    EXPECT_EQ(notification.method(), QString("testMethod"));
    EXPECT_EQ(notification.params(), params);
    EXPECT_TRUE(notification.hasParams());
    EXPECT_FALSE(notification.hasId());
    EXPECT_TRUE(notification.isValid());
}

TEST_F(TestJsonRpcNotification, SetGetMethod)
{
    JsonRpcNotification notification;
    
    notification.setMethod("newMethod");
    EXPECT_EQ(notification.method(), QString("newMethod"));
    
    notification.setMethod("anotherMethod");
    EXPECT_EQ(notification.method(), QString("anotherMethod"));
}

TEST_F(TestJsonRpcNotification, SetGetParams)
{
    JsonRpcNotification notification;
    
    QJsonObject params1;
    params1["key1"] = "value1";
    params1["key2"] = 42;
    
    notification.setParams(params1);
    EXPECT_EQ(notification.params(), params1);
    EXPECT_TRUE(notification.hasParams());
    
    QJsonObject params2;
    params2["key3"] = true;
    
    notification.setParams(params2);
    EXPECT_EQ(notification.params(), params2);
    EXPECT_TRUE(notification.hasParams());
    
    notification.setParams(QJsonObject());
    EXPECT_TRUE(notification.params().isEmpty());
    EXPECT_FALSE(notification.hasParams());
}

TEST_F(TestJsonRpcNotification, HasParams)
{
    JsonRpcNotification notification;
    
    EXPECT_FALSE(notification.hasParams());
    
    QJsonObject params;
    params["test"] = "value";
    notification.setParams(params);
    EXPECT_TRUE(notification.hasParams());
    
    notification.setParams(QJsonObject());
    EXPECT_FALSE(notification.hasParams());
}

TEST_F(TestJsonRpcNotification, ToJson)
{
    // Test without params
    JsonRpcNotification notification1("testMethod");
    QJsonObject json1 = notification1.toJson();
    
    EXPECT_EQ(json1["jsonrpc"].toString(), QString("2.0"));
    EXPECT_EQ(json1["method"].toString(), QString("testMethod"));
    EXPECT_FALSE(json1.contains("params"));
    EXPECT_FALSE(json1.contains("id"));
    
    // Test with params
    QJsonObject params;
    params["param1"] = "value1";
    params["param2"] = 123;
    
    JsonRpcNotification notification2("testMethod", params);
    QJsonObject json2 = notification2.toJson();
    
    EXPECT_EQ(json2["jsonrpc"].toString(), QString("2.0"));
    EXPECT_EQ(json2["method"].toString(), QString("testMethod"));
    EXPECT_TRUE(json2.contains("params"));
    EXPECT_EQ(json2["params"].toObject(), params);
    EXPECT_FALSE(json2.contains("id"));
}

TEST_F(TestJsonRpcNotification, FromJson)
{
    // Test valid notification without params
    QJsonObject json1;
    json1["jsonrpc"] = "2.0";
    json1["method"] = "testMethod";
    
    bool ok = false;
    JsonRpcNotification notification1 = JsonRpcNotification::fromJson(json1, &ok);
    
    EXPECT_TRUE(ok);
    EXPECT_EQ(notification1.method(), QString("testMethod"));
    EXPECT_FALSE(notification1.hasParams());
    EXPECT_FALSE(notification1.hasId());
    EXPECT_TRUE(notification1.isValid());
    
    // Test valid notification with params
    QJsonObject params;
    params["param1"] = "value1";
    params["param2"] = 123;
    
    QJsonObject json2;
    json2["jsonrpc"] = "2.0";
    json2["method"] = "testMethod";
    json2["params"] = params;
    
    JsonRpcNotification notification2 = JsonRpcNotification::fromJson(json2, &ok);
    
    EXPECT_TRUE(ok);
    EXPECT_EQ(notification2.method(), QString("testMethod"));
    EXPECT_EQ(notification2.params(), params);
    EXPECT_TRUE(notification2.hasParams());
    EXPECT_FALSE(notification2.hasId());
    EXPECT_TRUE(notification2.isValid());
}

TEST_F(TestJsonRpcNotification, FromJsonInvalid)
{
    bool ok = true;
    
    // Test missing jsonrpc field
    QJsonObject json1;
    json1["method"] = "testMethod";
    
    JsonRpcNotification notification1 = JsonRpcNotification::fromJson(json1, &ok);
    EXPECT_FALSE(ok);
    
    // Test wrong jsonrpc version
    QJsonObject json2;
    json2["jsonrpc"] = "1.0";
    json2["method"] = "testMethod";
    
    JsonRpcNotification notification2 = JsonRpcNotification::fromJson(json2, &ok);
    EXPECT_FALSE(ok);
    
    // Test missing method field
    QJsonObject json3;
    json3["jsonrpc"] = "2.0";
    
    JsonRpcNotification notification3 = JsonRpcNotification::fromJson(json3, &ok);
    EXPECT_FALSE(ok);
    
    // Test non-string method
    QJsonObject json4;
    json4["jsonrpc"] = "2.0";
    json4["method"] = 123;
    
    JsonRpcNotification notification4 = JsonRpcNotification::fromJson(json4, &ok);
    EXPECT_FALSE(ok);
    
    // Test with id field (should be invalid for notification)
    QJsonObject json5;
    json5["jsonrpc"] = "2.0";
    json5["method"] = "testMethod";
    json5["id"] = "test-id";
    
    JsonRpcNotification notification5 = JsonRpcNotification::fromJson(json5, &ok);
    EXPECT_FALSE(ok);
    
    // Test invalid params type
    QJsonObject json6;
    json6["jsonrpc"] = "2.0";
    json6["method"] = "testMethod";
    json6["params"] = QJsonArray();
    
    JsonRpcNotification notification6 = JsonRpcNotification::fromJson(json6, &ok);
    EXPECT_FALSE(ok);
}

TEST_F(TestJsonRpcNotification, IsValid)
{
    // Valid notification
    JsonRpcNotification notification1("testMethod");
    EXPECT_TRUE(notification1.isValid());
    
    // Valid notification with params
    QJsonObject params;
    params["param"] = "value";
    JsonRpcNotification notification2("testMethod", params);
    EXPECT_TRUE(notification2.isValid());
}

TEST_F(TestJsonRpcNotification, IsValidInvalid)
{
    // Invalid - empty method
    JsonRpcNotification notification1;
    EXPECT_FALSE(notification1.isValid());
    
    // Invalid - has ID (should not happen for notification)
    JsonRpcNotification notification2("testMethod");
    notification2.setId("test-id");
    EXPECT_FALSE(notification2.isValid());
}

